package com.utils.catche;

import java.util.Set;
import java.util.concurrent.Callable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.stereotype.Component;

import com.utils.redis.BaseRedisSupport;
import org.springframework.util.SerializationUtils;
import redis.clients.jedis.Jedis;
import redis.clients.util.SafeEncoder;

/**
 * @author: dingjiejun
 * @version: 1.0
 * @date: 2017/5/25
 */
@Component("redisCache")
public class RedisCacheProvider extends BaseRedisSupport implements CacheSupport, InitializingBean {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private String name;

//	@Override
//	public void clear() {
//		// TODO Auto-generated method stub
//
//	}
//
//	@Override
//	public void evict(Object arg0) {
//		// TODO Auto-generated method stub
//
//	}
//
//	@Override
//	public ValueWrapper get(Object arg0) {
//		// TODO Auto-generated method stub
//		return null;
//	}
//
//	@Override
//	public <T> T get(Object arg0, Class<T> arg1) {
//		// TODO Auto-generated method stub
//		return null;
//	}
//
//	@Override
//	public <T> T get(Object arg0, Callable<T> arg1) {
//		// TODO Auto-generated method stub
//		return null;
//	}
//
//	@Override
//	public String getName() {
//		// TODO Auto-generated method stub
//		return null;
//	}
//
//	@Override
//	public Object getNativeCache() {
//		// TODO Auto-generated method stub
//		return null;
//	}
//
//	@Override
//	public void put(Object arg0, Object arg1) {
//		// TODO Auto-generated method stub
//
//	}
//
//	@Override
//	public ValueWrapper putIfAbsent(Object arg0, Object arg1) {
//		// TODO Auto-generated method stub
//		return null;
//	}
//
//	@Override
//	public void afterPropertiesSet() throws Exception {
//		// TODO Auto-generated method stub
//
//	}
//
//	@Override
//	public void put(String key, Object value) {
//		// TODO Auto-generated method stub
//
//	}
//
//	@Override
//	public void put(String key, Object value, int timeToIdle) {
//		// TODO Auto-generated method stub
//
//	}
//
//	@Override
//	public Object get(String key) {
//		// TODO Auto-generated method stub
//		return null;
//	}
//
//	@Override
//	public Object get(String key, int timeToIdle) {
//		// TODO Auto-generated method stub
//		return null;
//	}
//
//	@Override
//	public void remove(String... keys) {
//		// TODO Auto-generated method stub
//
//	}
//
//	@Override
//	public boolean hasKey(String key) {
//		// TODO Auto-generated method stub
//		return false;
//	}
//
//	@Override
//	public void putSet(String key, String... values) {
//		// TODO Auto-generated method stub
//
//	}
//
//	@Override
//	public boolean isKeyInSet(String key, String... values) {
//		// TODO Auto-generated method stub
//		return false;
//	}
//
//	@Override
//	public Set<String> getSet(String key) {
//		// TODO Auto-generated method stub
//		return null;
//	}
//
//	@Override
//	public void removeSetValue(String key, String... values) {
//		// TODO Auto-generated method stub
//
//	}
//
//	@Override
//	public void putMap(String key, String field, String value) {
//		// TODO Auto-generated method stub
//
//	}
//
//	@Override
//	public String getMapValue(String key, String field) {
//		// TODO Auto-generated method stub
//		return null;
//	}
//
//	@Override
//	public void removeMapField(String key, String field) {
//		// TODO Auto-generated method stub
//
//	}

    @Value("${module.cache.redis.cluster:false}")
    @Override
    public void setCluster(boolean cluster) {
        this.cluster = cluster;
    }

    @Value("${module.cache.redis.address:}")
    @Override
    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    @Value("${module.cache.redis.password:}")
    public void setPassword(String password) {
        this.password = password;
    }

    @Value("${module.cache.redis.maxTotal:150}")
    @Override
    public void setMaxTotal(int maxTotal) {
        this.maxTotal = maxTotal;
    }

    @Value("${module.cache.redis.maxIdle:50}")
    @Override
    public void setMaxIdle(int maxIdle) {
        this.maxIdle = maxIdle;
    }

    @Value("${module.cache.redis.minIdle:2}")
    @Override
    public void setMinIdle(int minIdle) {
        this.minIdle = minIdle;
    }

    @Value("${module.cache.redis.maxWaitMillis:5000}")
    @Override
    public void setMaxWaitMillis(int maxWaitMillis) {
        this.maxWaitMillis = maxWaitMillis;
    }

    @Value("${module.cache.redis.testOnCreate:true}")
    @Override
    public void setTestOnCreate(boolean testOnCreate) {
        this.testOnCreate = testOnCreate;
    }

    @Value("${module.cache.redis.testOnBorrow:false}")
    @Override
    public void setTestOnBorrow(boolean testOnBorrow) {
        this.testOnBorrow = testOnBorrow;
    }

    @Value("${module.cache.redis.testOnReturn:false}")
    @Override
    public void setTestOnReturn(boolean testOnReturn) {
        this.testOnReturn = testOnReturn;
    }

    @Value("${module.cache.redis.testWhileIdle:true}")
    @Override
    public void setTestWhileIdle(boolean testWhileIdle) {
        this.testWhileIdle = testWhileIdle;
    }

    @Value("${module.cache.redis.timeBetweenEvictionRunsMillis:30000}")
    @Override
    public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
    }

    @Value("${module.cache.redis.numTestsPerEvictionRun:10}")
    @Override
    public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
        this.numTestsPerEvictionRun = numTestsPerEvictionRun;
    }

    @Value("${module.cache.redis.minEvictableIdleTimeMillis:30000}")
    @Override
    public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
    }

    @Value("${module.cache.redis.softMinEvictableIdleTimeMillis:1800000}")
    @Override
    public void setSoftMinEvictableIdleTimeMillis(long softMinEvictableIdleTimeMillis) {
        this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
    }

    @Value("${module.cache.redis.timeout:6000}")
    @Override
    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    @Value("${module.cache.redis.maxAttempts:3}")
    @Override
    public void setMaxAttempts(int maxAttempts) {
        this.maxAttempts = maxAttempts;
    }

    @Value("${module.cache.redis.name:remote}")
    public void setName(String name) {
        this.name = name ;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public void afterPropertiesSet() {
        super.createConnection();
    }

    /**
     * 存入缓存对象
     *
     * @param key
     * @param value
     **/
    @Override
    public void put(String key, Object value) {
        put(key, value, -1);
    }

    /**
     * 存入缓存对象，带过期时间（闲置时间）
     *
     * @param key
     * @param value
     * @param timeToIdle
     **/
    @Override
    public void put(String key, Object value, int timeToIdle) {
        byte[] keyBytes = SafeEncoder.encode(key);
        byte[] valueBytes = SerializeUtil.serialize(value);
        if (cluster) {
            if (timeToIdle > 0) {
                jedisCluster.setex(keyBytes, timeToIdle, valueBytes);
            } else {
                jedisCluster.set(keyBytes, valueBytes);
            }
        } else {
            Jedis jedis = getJedis();
            if (jedis == null) {
                return;
            }
            try {
                if (timeToIdle > 0) {
                    jedis.setex(keyBytes, timeToIdle, valueBytes);
                } else {
                    jedis.set(keyBytes, valueBytes);
                }
            } finally {
                returnClient(jedis);
            }
        }
    }

    /**
     * 获取缓存对象
     *
     * @param key
     * @return
     **/
    @Override
    public Object get(String key) {
        return get(key, -1);
    }

    /**
     * 获取缓存对象并更新过期时间
     *
     * @param key
     * @param timeToIdle
     * @return
     **/
    @Override
    public Object get(String key, int timeToIdle) {
        Object value = null;
        byte[] keyBytes = SafeEncoder.encode(key);
        if (cluster) {
            byte[] bytes = jedisCluster.get(keyBytes);
            if (bytes != null) {
                value = SerializeUtil.unserialize(bytes);
                if (timeToIdle > 0) {
                    jedisCluster.expire(keyBytes, timeToIdle);
                }
            }
        } else {
            Jedis jedis = getJedis();
            if (jedis != null) {
                try {
                    byte[] bytes = jedis.get(keyBytes);
                    if (bytes != null) {
                        value = SerializeUtil.unserialize(bytes);
                        if (timeToIdle > 0) {
                            jedis.expire(keyBytes, timeToIdle);
                        }
                    }
                } finally {
                    returnClient(jedis);
                }
            }
        }
        return value;
    }

    /**
     * 移除缓存
     *
     * @param keys
     **/
    @Override
    public void remove(String... keys) {
        if (cluster) {
            jedisCluster.del(keys);
        } else {
            Jedis jedis = getJedis();
            if (jedis != null) {
                try {
                    jedis.del(keys);
                } finally {
                    returnClient(jedis);
                }
            }
        }
    }

    /**
     * 判断缓存是否存在
     *
     * @param key
     * @return
     **/
    @Override
    public boolean hasKey(String key) {
        boolean isExists = false;
        if (cluster) {
            isExists = jedisCluster.exists(key);
        } else {
            Jedis jedis = getJedis();
            if (jedis != null) {
                try {
                    isExists = jedis.exists(key);
                } finally {
                    returnClient(jedis);
                }
            }
        }
        return isExists;
    }

    /**
     * 在Set中添加数据
     *
     * @param key
     * @param values
     **/
    @Override
    public void putSet(String key, String... values) {
        if (cluster) {
            jedisCluster.sadd(key, values);
        } else {
            Jedis jedis = getJedis();
            if (jedis != null) {
                try {
                    jedis.sadd(key, values);
                } finally {
                    returnClient(jedis);
                }
            }
        }
    }

    /**
     * 判断value在Set中存在
     *
     * @param key
     * @param values
     * @return
     **/
    @Override
    public boolean isKeyInSet(String key, String... values) {
        boolean hasKey = false;
        if (cluster) {
            for (String value : values) {
                hasKey = jedisCluster.sismember(key, value);
                if (hasKey) {
                    break;
                }
            }
        } else {
            Jedis jedis = getJedis();
            if (jedis != null) {
                try {
                    for (String value : values) {
                        hasKey = jedis.sismember(key, value);
                        if (hasKey) {
                            break;
                        }
                    }
                } finally {
                    returnClient(jedis);
                }
            }
        }
        return hasKey;
    }

    /**
     * 获取Set数据
     *
     * @param key
     * @return
     **/
    @Override
    public Set<String> getSet(String key) {
        Set<String> set = null;
        if (cluster) {
            set = jedisCluster.smembers(key);
        } else {
            Jedis jedis = getJedis();
            if (jedis != null) {
                try {
                    set = jedis.smembers(key);
                } finally {
                    returnClient(jedis);
                }
            }
        }
        return set;
    }

    /**
     * 从Set中删除值
     *
     * @param key
     * @param values
     **/
    @Override
    public void removeSetValue(String key, String... values) {
        if (cluster) {
            jedisCluster.srem(key, values);
        } else {
            Jedis jedis = getJedis();
            if (jedis != null) {
                try {
                    jedis.srem(key, values);
                } finally {
                    returnClient(jedis);
                }
            }
        }
    }

    /**
     * 在Map中添加数据(字符串)
     *
     * @param key
     * @param field
     * @param value
     **/
    @Override
    public void putMap(String key, String field, String value) {
        if (cluster) {
            jedisCluster.hset(key, field, value);
        } else {
            Jedis jedis = getJedis();
            if (jedis != null) {
                try {
                    jedis.hset(key, field, value);
                } finally {
                    returnClient(jedis);
                }
            }
        }
    }

    /**
     * 获取map中的值
     *
     * @param key
     * @param field
     * @return
     **/
    @Override
    public String getMapValue(String key, String field) {
        String value = null;
        if (cluster) {
            value = jedisCluster.hget(key, field);
        } else {
            Jedis jedis = getJedis();
            if (jedis != null) {
                try {
                    value = jedis.hget(key, field);
                } finally {
                    returnClient(jedis);
                }
            }
        }
        return value;
    }

    /**
     * 从Map中删除字段
     *
     * @param key
     * @param field
     **/
    @Override
    public void removeMapField(String key, String field) {
        if (cluster) {
            jedisCluster.hdel(key, field);
        } else {
            Jedis jedis = getJedis();
            if (jedis != null) {
                try {
                    jedis.hdel(key, field);
                } finally {
                    returnClient(jedis);
                }
            }
        }
    }

    @Override
    public Object getNativeCache() {
        if (cluster) {
            return jedisCluster;
        } else {
            return getJedis();
        }
    }

    @Override
    public ValueWrapper get(Object key) {
        Object value = get(key.toString());
        if(value==null){
            return null;
        }
        SimpleValueWrapper vw = new SimpleValueWrapper(value);
        return vw;
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T get(Object key, Class<T> type) {
        Object value = get(key.toString());
        return (T)value;
    }

    @Override
    public <T> T get(Object key, Callable<T> valueLoader) {
        return null;
    }

    @Override
    public void put(Object key, Object value) {
        if(value==null){
            remove(key.toString());
        }else{
            put(key.toString(),value);
        }
    }

    @Override
    public ValueWrapper putIfAbsent(Object key, Object value) {
        if(hasKey(key.toString())){
            return get(key);
        }else{
            if(value==null){
                remove(key.toString());
                return null;
            }else{
                put(key.toString(),value);
                SimpleValueWrapper vw = new SimpleValueWrapper(value);
                return vw;
            }
        }
    }

    @Override
    public void evict(Object key) {
        remove(key.toString());
    }

    @Override
    public void clear() {
        //安全考虑不做处理
    }
}
